//
//  Notification.swift
//  soapp
//
//  Created by zhuxietong on 2017/2/7.
//  Copyright © 2017年 zhuxietong. All rights reserved.
//

import Foundation
import UIKit


public protocol NotifyType{
 var name:Notification.Name{get}
}


public enum AppDelegateNotice:String,NotifyType{
    case applicationDidBecomeActive = "applicationDidBecomeActive"
    case applicationWillResignActive = "applicationWillResignActive"
    case applicationDidEnterBackground = "applicationDidEnterBackground"
    case applicationWillEnterForeground = "applicationWillEnterForeground"
    case applicationWillTerminate = "applicationWillTerminate"
    
    public static func notice(name:Notification.Name) ->AppDelegateNotice?{
        let str = name.rawValue.replace(byReg: "AppDelegateNotice.", tag: "")
        let notice = AppDelegateNotice(rawValue: str)
        return notice
    }
    
    public var name: Notification.Name{
        return "AppDelegateNotice.\(self.rawValue)".notice_name
    }
}


public func __post(notify:NotifyType,object:Any?=nil,userInfo:[String:Any]?=nil){
    NotificationCenter.default.post(name: notify.name, object: object, userInfo: userInfo)
}




extension String{
    public var notice_name:NSNotification.Name{
        get{
            return NSNotification.Name(rawValue: self)
        }
    }
}


extension UIViewController{
    private struct __AssociatedKeys {
        static var notify_key = "__easy_notify_key"
    }
    
    public var __notice: EasyNotification {
        get {
            if let obj = objc_getAssociatedObject(self, &__AssociatedKeys.notify_key) as? EasyNotification
            {
                return obj
            }
            let obj = EasyNotification()
            self.__notice = obj
            return obj
            
        }
        set {
            objc_setAssociatedObject(self, &__AssociatedKeys.notify_key, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    
}


public typealias NotificationTask = (notifyType:NotifyType,action:(_:Notification) ->Void)

public class EasyNotification {
    public var model:[String:(_:Notification) ->Void] = [:]
    public var tasks:[NotificationTask] = []
    
    @discardableResult
    public func add(task:NotificationTask) ->EasyNotification{
        remove(type: task.notifyType)
        model[task.notifyType.name.rawValue] = task.action
        NotificationCenter.default.addObserver(self, selector: #selector(__receive(_:)), name: task.notifyType.name, object: nil)
        return self
    }
    
    public func remove(type:NotifyType){
        var index:Int? = nil
        let notice = type.name.rawValue
        var i = 0
        for one in notices{
            if notice == one.name.rawValue{
                index = i
            }
            i = i + 1
        }
        if let index_ = index{
            notices.remove(at: i)
            NotificationCenter.default.removeObserver(self, name: type.name, object: nil)
        }
        if model.keys.contains(type.name.rawValue){
            model.removeValue(forKey: type.name.rawValue)
            NotificationCenter.default.removeObserver(self, name: type.name, object: nil)

        }
    }
    

    
    public var notices = [NotifyType]()
    
    public var receiveNotify:(NotifyType,Notification)->Void = {_,_ in }
    
    
    
    public init()
    {
        
    }
    
    public func observer(_ notice:NotifyType...,acition:@escaping (NotifyType,Notification)->Void) {
        
//        notices = notice
        for one in notice{
            remove(type: one)
        }
        notices = notice
     
       
        for one in notices{

            NotificationCenter.default.addObserver(self, selector: #selector(__receive(_:)), name: one.name, object: nil)
//            notices.append(one)
        }
        self.receiveNotify = acition
    }
    
    public func remove(_ notice:NotifyType...) {
        for one in notice{
            let notice_names = notice.map { (noty) -> String in
                noty.name.rawValue
            }
            if notice_names.contains(one.name.rawValue)
            {
                NotificationCenter.default.removeObserver(self, name: one.name, object: nil)
            }
        }
        self.receiveNotify = {_,_  in}
    }
    
    
    @objc func __receive(_ notify:Notification){
        for one in self.notices{
            if one.name == notify.name
            {
                self.receiveNotify(one, notify)
            }
        }
        let keys = model.keys
        for k in keys{
            if k == notify.name.rawValue
            {
                guard let block = model[k] else { return }
                block(notify)
            }
        }
    }
    
    deinit {
        for one in notices{
            NotificationCenter.default.removeObserver(self, name: one.name, object: nil)
        }
        let keys = model.keys
        for k in keys {
            NotificationCenter.default.removeObserver(self, name: k.notice_name, object: nil)
        }
    }
    
    
}
